/**
 * @file EventBase.h
 * @author  事件定义的基类，里面的函数我也没怎么看过
 * @brief 
 * @version 1.0
 * @date 2020-07-28
 * 
 * @copyright Copyright (c) 2020
 * 
 */

#pragma once

#include <boost/function.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/thread.hpp>
#include <iostream>
#include <memory>
#include "modules/AssistModule/LogModule.h"

namespace behavior_controller
{
    template <typename Evt>
    class EventGuard
    {
    public:
        EventGuard(const Evt &evt) : evt_ptr(&evt) {}
        ~EventGuard() { evt_ptr->PostReceive(); }

    private:
        const Evt *const evt_ptr;
    };

    template <typename Derived>
    class EventBase : public std::enable_shared_from_this<Derived>
    {
    public:
        static boost::signals2::connection Register(std::function<void(const std::shared_ptr<Derived> &)> func)
        {
            return signal_.connect(func);
        }

        template <typename... Args>
        static std::shared_ptr<Derived> New(Args &&... args)
        {
            return std::make_shared<Derived>(args...);
        }

        void Push()
        {
            signal_(((Derived *)this)->shared_from_this());
        }

        template <typename... Args>
        static std::shared_ptr<Derived> Send(Args &&... args)
        {
            auto evt_ptr = New(args...);
            evt_ptr->Push();
            return evt_ptr;
        }

        virtual void PreSend() {}
        virtual void PostReceive() const {}

    private:
        static boost::mutex mtx_;
        static boost::signals2::signal<void(const std::shared_ptr<Derived> &)>
            signal_;
    };

    template <typename Derived>
    boost::mutex EventBase<Derived>::mtx_;
    template <typename Derived>
    boost::signals2::signal<void(const std::shared_ptr<Derived> &)>
        EventBase<Derived>::signal_;

    class EventDefault
    {
    public:
        explicit EventDefault() = default;
        virtual ~EventDefault() = default;
    };

    template <class Derived>
    class EventData : public EventDefault
    {
    public:
        explicit EventData(const Derived &_data) : data(_data)
        {
        }
        Derived data;
    };

    namespace occur
    {

        class Heartbeat : public EventBase<Heartbeat>
        {
        };

        struct HeartbeatCallback : public EventBase<HeartbeatCallback>
        {
            HeartbeatCallback(std::string name) : module_name(name) {}
            std::string module_name;
        };

    } // namespace occur

} // namespace behavior_controller